import React, { Component } from 'react';
import * as PropTypes from 'prop-types';
import graphql from 'babel-plugin-relay/macro';
import { createFragmentContainer } from 'react-relay';
import { Form, Formik, Field } from 'formik';
import {
  assoc, compose, pick, pipe,
} from 'ramda';
import * as Yup from 'yup';
import inject18n from '../../../../components/i18n';
import DatePickerField from '../../../../components/DatePickerField';
import { SubscriptionFocus } from '../../../../components/Subscription';
import { commitMutation } from '../../../../relay/environment';
import { dateFormat } from '../../../../utils/Time';
import OpenVocabField from '../../common/form/OpenVocabField';
import SwitchField from '../../../../components/SwitchField';

const malwareMutationFieldPatch = graphql`
  mutation MalwareEditionDetailsFieldPatchMutation(
    $id: ID!
    $input: EditInput!
  ) {
    malwareEdit(id: $id) {
      fieldPatch(input: $input) {
        ...MalwareEditionDetails_malware
        ...Malware_malware
      }
    }
  }
`;

const malwareEditionDetailsFocus = graphql`
  mutation MalwareEditionDetailsFocusMutation($id: ID!, $input: EditContext!) {
    malwareEdit(id: $id) {
      contextPatch(input: $input) {
        id
      }
    }
  }
`;

const malwareValidation = (t) => Yup.object().shape({
  is_family: Yup.boolean(),
  first_seen: Yup.date().typeError(
    t('The value must be a date (YYYY-MM-DD)'),
  ),
  last_seen: Yup.date().typeError(t('The value must be a date (YYYY-MM-DD)')),
  architecture_execution_envs: Yup.array(),
  implementation_languages: Yup.array(),
  capabilities: Yup.array(),
});

class MalwareEditionDetailsComponent extends Component {
  handleChangeFocus(name) {
    commitMutation({
      mutation: malwareEditionDetailsFocus,
      variables: {
        id: this.props.malware.id,
        input: {
          focusOn: name,
        },
      },
    });
  }

  handleSubmitField(name, value) {
    malwareValidation(this.props.t)
      .validateAt(name, { [name]: value })
      .then(() => {
        commitMutation({
          mutation: malwareMutationFieldPatch,
          variables: {
            id: this.props.malware.id,
            input: { key: name, value },
          },
        });
      })
      .catch(() => false);
  }

  render() {
    const { t, malware, context } = this.props;
    const initialValues = pipe(
      assoc('first_seen', dateFormat(malware.first_seen)),
      assoc('last_seen', dateFormat(malware.last_seen)),
      assoc(
        'architecture_execution_envs',
        malware.architecture_execution_envs
          ? malware.architecture_execution_envs
          : [],
      ),
      assoc(
        'implementation_languages',
        malware.implementation_languages ? malware.implementation_languages : [],
      ),
      assoc('capabilities', malware.capabilities ? malware.capabilities : []),
      pick([
        'first_seen',
        'last_seen',
        'architecture_execution_envs',
        'implementation_languages',
        'capabilities',
        'is_family',
      ]),
    )(malware);

    return (
      <Formik
        enableReinitialize={true}
        initialValues={initialValues}
        validationSchema={malwareValidation(t)}
        onSubmit={() => true}
      >
        {() => (
          <Form style={{ margin: '20px 0 20px 0' }}>
            <Field
              component={DatePickerField}
              name="first_seen"
              label={t('First seen')}
              invalidDateMessage={t('The value must be a date (YYYY-MM-DD)')}
              fullWidth={true}
              onFocus={this.handleChangeFocus.bind(this)}
              onSubmit={this.handleSubmitField.bind(this)}
              helperText={
                <SubscriptionFocus context={context} fieldName="first_seen" />
              }
            />
            <Field
              component={DatePickerField}
              name="last_seen"
              label={t('Last seen')}
              invalidDateMessage={t('The value must be a date (YYYY-MM-DD)')}
              fullWidth={true}
              style={{ marginTop: 20 }}
              onFocus={this.handleChangeFocus.bind(this)}
              onSubmit={this.handleSubmitField.bind(this)}
              helperText={
                <SubscriptionFocus context={context} fieldName="last_seen" />
              }
            />
            <OpenVocabField
              label={t('Architecture execution env.')}
              type="processor-architecture-ov"
              name="architecture_execution_envs"
              onFocus={this.handleChangeFocus.bind(this)}
              onChange={this.handleSubmitField.bind(this)}
              containerstyle={{ marginTop: 20, width: '100%' }}
              variant="edit"
              multiple={true}
              editContext={context}
            />
            <OpenVocabField
              label={t('Architecture execution env.')}
              type="implementation-language-ov"
              name="implementation_languages"
              onFocus={this.handleChangeFocus.bind(this)}
              onChange={this.handleSubmitField.bind(this)}
              containerstyle={{ marginTop: 20, width: '100%' }}
              variant="edit"
              multiple={true}
              editContext={context}
            />
            <OpenVocabField
              label={t('Capabilities')}
              type="malware-capabilities-ov"
              name="capabilities"
              onFocus={this.handleChangeFocus.bind(this)}
              onChange={this.handleSubmitField.bind(this)}
              containerstyle={{ marginTop: 20, width: '100%' }}
              variant="edit"
              multiple={true}
              editContext={context}
            />
            <Field
              component={SwitchField}
              type="checkbox"
              name="is_family"
              label={t('Is family?')}
              containerstyle={{ marginTop: 20 }}
              onChange={this.handleSubmitField.bind(this)}
              helperText={
                <SubscriptionFocus context={context} fieldName="is_family" />
              }
            />
          </Form>
        )}
      </Formik>
    );
  }
}

MalwareEditionDetailsComponent.propTypes = {
  t: PropTypes.func,
  malware: PropTypes.object,
  context: PropTypes.array,
};

const MalwareEditionDetails = createFragmentContainer(
  MalwareEditionDetailsComponent,
  {
    malware: graphql`
      fragment MalwareEditionDetails_malware on Malware {
        id
        is_family
        first_seen
        last_seen
        architecture_execution_envs
        implementation_languages
        capabilities
      }
    `,
  },
);

export default compose(inject18n)(MalwareEditionDetails);
